/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2022. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * Description:
 * Author: huawei
 * Create: 2019-10-15
 */
#include <linux/version.h>
#include <linux/mm.h>
#include <linux/mm_types.h>
#include <linux/cgroup.h>
#include <linux/memcontrol.h>
#include "svm_proc_mng.h"
#include "svm_cgroup_mng.h"

struct mem_cgroup *devmm_enable_cgroup(struct mem_cgroup **memcg, pid_t pid)
{
    return NULL;
}

void devmm_disable_cgroup(struct mem_cgroup *memcg, struct mem_cgroup *old_memcg)
{
}

void devmm_split_page_memcg(struct page *page, u64 page_num)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
#ifdef CONFIG_MEMCG
    struct page *cur_page = NULL;
    u64 pfn, i;
    /*
     * split_page do not change mem_cgroup of page[1-n]
     * if app run in docker can not statistics free page num
     * set page[0] mem_cgroup to page[1-n]
     */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
    if (page_memcg_check(page) == NULL) {
        return;
    }
#else
    if (page->mem_cgroup == NULL) {
        return;
    }
#endif
    pfn = page_to_pfn(page) + 1;
    for (i = 1; i < page_num; i++, pfn++) {
        cur_page = pfn_to_page(pfn);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
        if (page_memcg_check(cur_page) != NULL) {
            return;
        }
        cur_page->memcg_data = page->memcg_data | MEMCG_DATA_KMEM;
#else
        if (cur_page->mem_cgroup != NULL) {
            return;
        }
        cur_page->mem_cgroup = page->mem_cgroup;
        __SetPageKmemcg(cur_page);
#endif
    }
#endif
#endif
}

bool devmm_can_get_continuity_page(void)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 14, 0)
    /* just support PM, not support docker, if app run in docker can not statistics free page num */
    if (devmm_thread_is_run_in_docker() == true) {
        return false;
    }

    return true;
#else
    #ifdef CONFIG_MEMCG
        /* devmm_split_page_memcg to statistics free page num in docker */
        return true;
    #else
        /* just support PM, not support docker, if app run in docker can not statistics free page num */
        if (devmm_thread_is_run_in_docker() == true) {
            return false;
        }

        return true;
    #endif
#endif
}